package com.LeeCode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 大礼包
 */

public class Code638 {
    public static void main(String[] args) {

    }

    private Map<String, Integer> memo = new HashMap<>();

    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        // 预处理：过滤无效套餐
        List<List<Integer>> validSpecial = new ArrayList<>();
        for (List<Integer> offer : special) {
            if (isValidOffer(offer, price, needs)) {
                validSpecial.add(offer);
            }
        }

        return backtrace(price, validSpecial, needs);
    }

    private int backtrace(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        // 记忆化键值
        String key = needs.toString();
        if (memo.containsKey(key)) {
            return memo.get(key);
        }

        // 计算直接购买的费用（作为上界）
        int minCost = directBuy(price, needs);

        // 尝试每个套餐
        for (List<Integer> offer : special) {
            if (canUseOffer(offer, needs)) {
                // 使用套餐
                List<Integer> newNeeds = new ArrayList<>(needs);
                for (int i = 0; i < newNeeds.size(); i++) {
                    newNeeds.set(i, newNeeds.get(i) - offer.get(i));
                }

                // 递归计算剩余需求的最小费用
                int cost = offer.get(offer.size() - 1) + backtrace(price, special, newNeeds);
                minCost = Math.min(minCost, cost);
            }
        }

        memo.put(key, minCost);
        return minCost;
    }

    private boolean isValidOffer(List<Integer> offer, List<Integer> price, List<Integer> needs) {
        int offerPrice = offer.get(offer.size() - 1);
        int directPrice = 0;
        for (int i = 0; i < price.size(); i++) {
            if (offer.get(i) > needs.get(i)) return false;
            directPrice += offer.get(i) * price.get(i);
        }
        // 套餐价格应该比单独购买便宜才有意义
        return offerPrice < directPrice;
    }

    private boolean canUseOffer(List<Integer> offer, List<Integer> needs) {
        for (int i = 0; i < needs.size(); i++) {
            if (offer.get(i) > needs.get(i)) return false;
        }
        return true;
    }

    private int directBuy(List<Integer> price, List<Integer> needs) {
        int total = 0;
        for (int i = 0; i < price.size(); i++) {
            total += price.get(i) * needs.get(i);
        }
        return total;
    }
}
